package com.shycloud.mido.common.security.service;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.happy.zebra.admin.api.dto.UserInfo;
import com.happy.zebra.admin.api.entity.SysUser;
import com.happy.zebra.admin.api.feign.RemoteUserService;
import com.shycloud.mido.common.core.constant.CommonConstants;
import com.shycloud.mido.common.core.constant.SecurityConstants;
import com.shycloud.mido.common.core.exception.BusinessException;
import com.shycloud.mido.common.core.util.R;
import com.shycloud.mido.common.security.exception.ShyAuth2Exception;
import com.shycloud.mido.member.api.dto.MemberLoginInfo;
import com.shycloud.mido.member.api.entity.Member;
import com.shycloud.mido.member.api.feign.RemoteMemberService;
import com.shycloud.mido.member.api.vo.MemberDetailForLoginVO;
import com.shycloud.mido.opter.api.feign.RemoteOpterLoginService;
import com.shycloud.mido.organ.api.feign.RemoteLoginService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 用户详细信息
 *
 * @author npc
 */
@Slf4j
@Service
@AllArgsConstructor
public class ShyUserDetailsServiceImpl implements ShyUserDetailsService {

	private final RemoteUserService remoteUserService;
	private final RemoteMemberService remoteMemberService;
	private final CacheManager cacheManager;

	/**
	 * 用户密码登录
	 *
	 * @param username 用户名
	 * @return
	 * @throws UsernameNotFoundException
	 */
	@Override
	@SneakyThrows
	public UserDetails loadUserByUsername(String username) {


		String flg = "";

		if (StrUtil.startWithAny(username, "mobile@@")) {
			username = StrUtil.removePrefix(username, "mobile@@");
			Cache cache = cacheManager.getCache("member_details");

			R<MemberLoginInfo> result = remoteMemberService.info(username, SecurityConstants.FROM_IN);
			UserDetails userDetails = getMemberDetails(result);
			cache.put(username, userDetails);
			return userDetails;
		}

		//=================================== 小程序 登录  START=======================================================//
		if (StrUtil.startWithAny(username, "mini@@")) {
			username = StrUtil.removePrefix(username, "mini@@");
			Cache cache = cacheManager.getCache("member_details");

			R<MemberLoginInfo> result = remoteMemberService.info(username, SecurityConstants.FROM_IN);
			UserDetails userDetails = getMemberDetailsMini(result);
			cache.put(username, userDetails);
			return userDetails;
		}
		//=================================== 小程序 登录  E N D=======================================================//

		//=================================== 机构移动端 登录  START=======================================================//
		if (StrUtil.startWithAny(username, "organ@@")) {
			username = StrUtil.removePrefix(username, "organ@@");
			Cache cache = cacheManager.getCache("member_details");

			R<MemberLoginInfo> result = remoteMemberService.info(username, SecurityConstants.FROM_IN);
			UserDetails userDetails = getOrganMemberDetails(result);
			cache.put(username, userDetails);
			return userDetails;
		}
		//=================================== 机构移动端 登录  E N D=======================================================//

		//=================================== 运营商登录 START=====================================================//
		if (StrUtil.startWithAny(username, "opter@@")) {
			username = StrUtil.removePrefix(username, "opter@@");
			flg = "opt";
		}
		//=================================== 运营商登录 E-N-D=====================================================//

		Cache cache = cacheManager.getCache("user_details");
		R<UserInfo> result = remoteUserService.info(username, SecurityConstants.FROM_IN);
		UserDetails userDetails = getUserDetails(result, flg);
		cache.put(username, userDetails);
		return userDetails;
	}


	/**
	 * 根据社交登录code 登录
	 *
	 * @param inStr TYPE@CODE
	 * @return UserDetails
	 * @throws UsernameNotFoundException
	 */
	@Override
	@SneakyThrows
	public UserDetails loadUserByMobile(String inStr, String typeCode) {

		if ("wxCode".equals(typeCode)) {
			R<MemberLoginInfo> load = remoteMemberService.load(inStr, SecurityConstants.FROM_IN);
			return getMemberSocialDetailsWx(load);
		} else if ("miniCode".equals(typeCode)) {
			return getMemberDetailsMini(remoteMemberService.load(inStr, SecurityConstants.FROM_IN));
		} else if ("miniWxCode".equals(typeCode)) {
			R<MemberLoginInfo> load = remoteMemberService.load(inStr, SecurityConstants.FROM_IN);
			return getMemberDetailsMiniWx(load);
		} else {
			return getMemberSocialDetails(remoteMemberService.load(inStr, SecurityConstants.FROM_IN));
		}

	}

	/**
	 * 构建userdetails
	 *
	 * @param result 用户信息
	 * @return
	 */
	private UserDetails getMemberDetails(R<MemberLoginInfo> result) {

		if (result == null || result.getData() == null) {
			throw new UsernameNotFoundException("用户不存在");
		}

		MemberLoginInfo memberLoginInfo = result.getData();

		MemberDetailForLoginVO member = memberLoginInfo.getMember();

		if (member == null) {
			throw new ShyAuth2Exception("账号不存在");
		}
		if ("2".equals(member.getStatus())) {
			throw new ShyAuth2Exception("账号不存在");
		}

		boolean enabled = StrUtil.equals(member.getLockFlag(), CommonConstants.STATUS_NORMAL);

		// 构造security用户
		return new ShyMember(
				member.getId(),
				member.getUsername(),
				member.getPhone(),
				"mobile@@" + member.getUsername(),
				SecurityConstants.BCRYPT + member.getPassword(),
				member.getOrgId(),
				member.getOrgName(),
				member.getSex(),
				member.getBirthday(),
				member.getIsTeacher(),
				member.getShowname(),
				member.getAvatar(),
				member.getAccount(),
				"1",
				member.getWxFlg(),
				member.getWxOpenid(),
				enabled,
				true, true, !CommonConstants.STATUS_LOCK.equals(member.getLockFlag()), AuthorityUtils.NO_AUTHORITIES);
	}

	private UserDetails getMemberDetailsMini(R<MemberLoginInfo> result) {

		if (result == null || result.getData() == null) {
			throw new UsernameNotFoundException("用户不存在");
		}

		MemberLoginInfo memberLoginInfo = result.getData();

		MemberDetailForLoginVO member = memberLoginInfo.getMember();

		if (member == null) {
			throw new ShyAuth2Exception("账号不存在");
		}
		if ("2".equals(member.getStatus())) {
			throw new ShyAuth2Exception("账号不存在");
		}

		boolean enabled = StrUtil.equals(member.getLockFlag(), CommonConstants.STATUS_NORMAL);

		// 构造security用户
		return new ShyMember(
				member.getId(),
				member.getUsername(),
				member.getPhone(),
				"mini@@" + member.getUsername(),
				SecurityConstants.BCRYPT + member.getPassword(),
				member.getOrgId(),
				member.getOrgName(),
				member.getSex(),
				member.getBirthday(),
				member.getIsTeacher(),
				member.getShowname(),
				member.getAvatar(),
				member.getAccount(),
				"1",
				member.getWxFlg(),
				member.getWxOpenid(),
				enabled,
				true, true, !CommonConstants.STATUS_LOCK.equals(member.getLockFlag()), AuthorityUtils.NO_AUTHORITIES);
	}

	private UserDetails getMemberDetailsMiniWx(R<MemberLoginInfo> result) {

		if (result == null || result.getData() == null) {
			throw new UsernameNotFoundException("用户不存在");
		}

		MemberLoginInfo memberLoginInfo = result.getData();

		MemberDetailForLoginVO member = memberLoginInfo.getMember();

		if (member == null) {
			throw new ShyAuth2Exception("账号不存在");
		}

		if ("2".equals(member.getStatus())) {
			throw new ShyAuth2Exception("账号不存在");
		}

		boolean enabled = StrUtil.equals(member.getLockFlag(), CommonConstants.STATUS_NORMAL);

		// 构造security用户
		return new ShyMember(
				member.getId(),
				member.getUsername(),
				member.getPhone(),
				"mini@@" + member.getUsername(),
				SecurityConstants.BCRYPT + member.getPassword(),
				member.getOrgId(),
				member.getOrgName(),
				member.getSex(),
				member.getBirthday(),
				member.getIsTeacher(),
				member.getShowname(),
				member.getAvatar(),
				member.getAccount(),
				"2",
				member.getWxFlg(),
				member.getWxOpenid(),
				enabled,
				true, true, !CommonConstants.STATUS_LOCK.equals(member.getLockFlag()), AuthorityUtils.NO_AUTHORITIES);
	}

	private UserDetails getMemberSocialDetails(R<MemberLoginInfo> result) {

		if (result == null || result.getData() == null) {
			//服务异常
			throw new ShyAuth2Exception("-1", "-1");
		}

		MemberLoginInfo memberLoginInfo = result.getData();

		if (memberLoginInfo.getStatus().equals("-2")) {
			//参数无效
			throw new ShyAuth2Exception("-1", "-1");
		}

		if (memberLoginInfo.getStatus().equals("-1")) {
			throw new ShyAuth2Exception("0", "-1");
		}

		if (memberLoginInfo.getStatus().equals("0")) {
			throw new ShyAuth2Exception(memberLoginInfo.getOpenId(), "0");
		}

		MemberDetailForLoginVO member = memberLoginInfo.getMember();

		boolean enabled = StrUtil.equals(member.getLockFlag(), CommonConstants.STATUS_NORMAL);

		// 构造security用户
		return new ShyMember(
				member.getId(),
				member.getUsername(),
				member.getPhone(),
				"mobile@@" + member.getUsername(),
				SecurityConstants.BCRYPT + member.getPassword(),
				member.getOrgId(),
				member.getOrgName(),
				member.getSex(),
				member.getBirthday(),
				member.getIsTeacher(),
				member.getShowname(),
				member.getAvatar(),
				member.getAccount(),
				"1",
				member.getWxFlg(),
				member.getWxOpenid(),
				enabled,
				true, true, !CommonConstants.STATUS_LOCK.equals(member.getLockFlag()), AuthorityUtils.NO_AUTHORITIES);
	}

	private UserDetails getMemberSocialDetailsWx(R<MemberLoginInfo> result) {

		if (result == null || result.getData() == null) {
			//服务异常
			throw new ShyAuth2Exception("-1", "-1");
		}

		MemberLoginInfo memberLoginInfo = result.getData();

		if (memberLoginInfo.getStatus().equals("-2")) {
			//参数无效
			throw new ShyAuth2Exception("-1", "-1");
		}

		if (memberLoginInfo.getStatus().equals("-1")) {
			throw new ShyAuth2Exception("0", "-1");
		}

		if (memberLoginInfo.getStatus().equals("0")) {
			throw new ShyAuth2Exception(memberLoginInfo.getOpenId(), "0");
		}

		if ("3".equals(memberLoginInfo.getStatus())) {
			throw new BusinessException(new R(3, "wx_not_bind," + memberLoginInfo.getOpenId(), memberLoginInfo.getOpenId()));
		}

		MemberDetailForLoginVO member = memberLoginInfo.getMember();

		boolean enabled = StrUtil.equals(member.getLockFlag(), CommonConstants.STATUS_NORMAL);

		// 构造security用户
		return new ShyMember(
				member.getId(),
				member.getUsername(),
				member.getPhone(),
				"mobile@@" + member.getUsername(),
				SecurityConstants.BCRYPT + member.getPassword(),
				member.getOrgId(),
				member.getOrgName(),
				member.getSex(),
				member.getBirthday(),
				member.getIsTeacher(),
				member.getShowname(),
				member.getAvatar(),
				member.getAccount(),
				"2",
				member.getWxFlg(),
				member.getWxOpenid(),
				enabled,
				true, true, !CommonConstants.STATUS_LOCK.equals(member.getLockFlag()), AuthorityUtils.NO_AUTHORITIES);
	}

	/**
	 * 构建userdetails
	 *
	 * @param result 用户信息
	 * @return
	 */
	private UserDetails getOrganMemberDetails(R<MemberLoginInfo> result) {
		if (result == null || result.getData() == null) {
			throw new UsernameNotFoundException("用户不存在");
		}

		if (result == null || result.getData() == null) {
			throw new UsernameNotFoundException("用户不存在");
		}

		MemberLoginInfo memberLoginInfo = result.getData();

		MemberDetailForLoginVO member = memberLoginInfo.getMember();

		if (member == null) {
			throw new ShyAuth2Exception("账号不存在");
		}
		if ("2".equals(member.getStatus())) {
			throw new ShyAuth2Exception("账号不存在");
		}

		boolean enabled = StrUtil.equals(member.getLockFlag(), CommonConstants.STATUS_NORMAL);

		// 构造security用户
		return new ShyMember(
				member.getId(),
				member.getUsername(),
				member.getPhone(),
				"mini@@" + member.getUsername(),
				SecurityConstants.BCRYPT + member.getPassword(),
				member.getOrgId(),
				member.getOrgName(),
				member.getSex(),
				member.getBirthday(),
				member.getIsTeacher(),
				member.getShowname(),
				member.getAvatar(),
				member.getAccount(),
				"1",
				member.getWxFlg(),
				member.getWxOpenid(),
				enabled,
				true, true, !CommonConstants.STATUS_LOCK.equals(member.getLockFlag()), AuthorityUtils.NO_AUTHORITIES);
	}

	private UserDetails getOpterMemberDetails(R<Member> result, String opterId) {
		if (result == null || result.getData() == null) {
			throw new UsernameNotFoundException("用户不存在");
		}

		Member member = result.getData();

		boolean enabled = StrUtil.equals(member.getLockFlag(), CommonConstants.STATUS_NORMAL);
		// 构造security用户

		return new ShyOpterMember(member.getId(), opterId, "opter@@" + member.getPhone(), SecurityConstants.BCRYPT + member.getPassword(), enabled,
				true, true, !CommonConstants.STATUS_LOCK.equals(member.getLockFlag()), AuthorityUtils.NO_AUTHORITIES);
	}

	/**
	 * 构建userdetails
	 *
	 * @param result 用户信息
	 * @return
	 */
	private UserDetails getUserDetails(R<UserInfo> result, String flg) {

		if (result == null || result.getData() == null) {
			throw new UsernameNotFoundException("用户不存在");
		}

		UserInfo info = result.getData();

		Integer[] roles = info.getRoles();

		System.out.println(roles);

		Set<String> dbAuthsSet = new HashSet<>();
		if (ArrayUtil.isNotEmpty(info.getRoles())) {
			// 获取角色
			Arrays.stream(info.getRoles()).forEach(roleId -> dbAuthsSet.add(SecurityConstants.ROLE + roleId));
			// 获取资源
			dbAuthsSet.addAll(Arrays.asList(info.getPermissions()));

		}

		Collection<? extends GrantedAuthority> authorities
				= AuthorityUtilsExt.createAuthorityListExt(flg, dbAuthsSet.toArray(new String[0]));

		SysUser user = info.getSysUser();
		boolean enabled = StrUtil.equals(user.getLockFlag(), CommonConstants.STATUS_NORMAL);

//		if ("opt".equals(flg)) {
//			authorities.remove("ROLE_16");
//		}

		// 构造security用户
		return new ShyUser(
				user.getUserId(),
				user.getDeptId(),
				user.getTenantId(),
				user.getUsername(),
				SecurityConstants.BCRYPT + user.getPassword(),
				100,
				enabled,
				true,
				true,
				!CommonConstants.STATUS_LOCK.equals(user.getLockFlag()),
				authorities);
	}
}